#include "ap3216c.h"

static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *device_id);
static int ap3216c_remove(struct i2c_client *client);

static int ap3216c_open(struct inode *inode, struct file *file);
static int ap3216c_release(struct inode *inode, struct file *file);
static ssize_t ap3216c_read(struct file *filp, char __user *user_buf, size_t cnt, loff_t *off);

//设备号
static dev_t ap3216c_num;
//class对象
static struct class *ap3216c_class;
//操作函数
static struct file_operations ap3216c_ops = {
	.owner = THIS_MODULE,
	.open = ap3216c_open,
	.read = ap3216c_read,
	.release = ap3216c_release,
};
//cdev对象
static struct cdev ap3216c_cdev;

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id ap3216c_of_match[] = {
	{.compatible = "alientek,ap3216c"},
	{ /* Sentinel */ }
};

//平台驱动
static struct i2c_driver ap3216c_driver = {
	.driver = {
		.name = "alientek,ap3216c",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = ap3216c_of_match,
	},
	.probe = ap3216c_probe,
	.remove = ap3216c_remove,
};

//ap3216c资源
static struct ap3216c_handle ap3216c_handle[AP3216C_NUMBER];

static int ap3216c_read_regs(struct i2c_client *client, uint8_t reg, uint8_t *data, uint8_t lenght)
{
	struct i2c_msg msg[2];

	//从机地址
	msg[0].addr = client->addr;
	//表示写
	msg[0].flags = 0;
	//buf是一个指针,指向了要发送的数据
	msg[0].buf = &reg;
	//msg[0].buf的数据长度
	msg[0].len = 1;

	msg[1].addr = client->addr;
	//表示读
	msg[1].flags = I2C_M_RD;
	msg[1].buf = data;
	msg[1].len = lenght;
	if(i2c_transfer(client->adapter, msg, 2)  == 2)
		return 0;
	else 
		return -EIO;
}

static int ap3216c_write_regs(struct i2c_client *client, uint8_t reg, uint8_t *data, uint8_t lenght)
{
	uint8_t buffer[256];
	struct i2c_msg msg[1];
	
	//只能用一个msg发送，分多个msg时msg衔接的时候不会等待设备的ACK信号，可能会导致失败
	buffer[0] = reg;
	memcpy(&buffer[1], data, lenght);
	//从机地址
	msg[0].addr = client->addr;
	//表示写
	msg[0].flags = 0;
	//buf是一个指针,指向了要发送的数据
	msg[0].buf = buffer;
	//msg[0].buf的数据长度
	msg[0].len = 1 + lenght;
	if(i2c_transfer(client->adapter, msg, 1)  == 1)
		return 0;
	else 
		return -EIO;
}

static int ap3216c_read_reg(struct i2c_client *client, uint8_t reg, uint8_t *data)
{
	return ap3216c_read_regs(client, reg, data, 1);
}

static int ap3216c_write_reg(struct i2c_client *client, uint8_t reg, uint8_t data)
{
	return ap3216c_write_regs(client, reg, &data, 1);
}

static int ap3216c_open(struct inode *inode, struct file *file)
{
	int result;
	uint32_t id;

	//提取设备ID
	id = MINOR(inode->i_rdev);
	if(id > AP3216C_NUMBER)
		return -EINVAL;

	//初始化AP3216C，然后开启ALS、PS+IR
	result = ap3216c_write_reg(ap3216c_handle[id].client, AP3216C_SYSTEMCONG, 0x04);
	if(result != 0)
		return result;
	mdelay(50);
	result = ap3216c_write_reg(ap3216c_handle[id].client, AP3216C_SYSTEMCONG, 0X03);
	if(result != 0)
		return result;
	mdelay(250);

	return 0;
}

static int ap3216c_release(struct inode *inode, struct file *file)
{
	return 0;
}

static ssize_t ap3216c_read(struct file *file, char __user *user_buf, size_t cnt, loff_t *off)
{
	int i;
	int result;
	uint32_t id;
	uint16_t data[3];
	uint8_t buffer[6];

	//提取设备ID
	id = MINOR(file->f_inode->i_rdev);
	if(id > AP3216C_NUMBER)
		return -EINVAL;

	/* 循环读取所有传感器数据 */
	for(i=0; i<6; i++) 
	{
		result = ap3216c_read_reg(ap3216c_handle[id].client, AP3216C_IRDATALOW+i, &buffer[i]);
		if(result != 0)
			return result;
	}

	if(buffer[0] & 0X80) /* IR_OF位为1,则数据无效 */
		data[0] = 0;
	else /* 读取IR传感器的数据*/
		data[0] = ((uint16_t)buffer[1] << 2) | (buffer[0] & 0X03);
	
	data[1] = ((uint16_t)buffer[3] << 8) | buffer[2]; /* 读取ALS传感器的数据 */
	
	if(buffer[4] & 0x40) /* IR_OF位为1,则数据无效 */
		data[2] = 0;
	else /* 读取PS传感器的数据 */
		data[2] = ((uint16_t)(buffer[5] & 0X3F) << 4) | (buffer[4] & 0X0F);

	result = copy_to_user(user_buf, data, sizeof(data));
	if(result != 0)
		return -EFAULT;

	return 6;
}

//设备和驱动匹配成功执行
static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *device_id)
{
	int result;
	uint32_t id;
	struct device *device;

	printk("%s\r\n", __FUNCTION__);

	//获取设备ID号
	result = of_property_read_u32(client->dev.of_node, "id", &id);
	if(result != 0)
	{
		printk("get dev id failed\r\n");
		return result;
	}
	if(id > AP3216C_NUMBER)
	{
		printk("dev id invalid\r\n");
		return -EINVAL;
	}

	//检查是否占用
	if(ap3216c_handle[id].use_flag) 
	{
		printk("dev id repetition\r\n");
		return -EINVAL;
	}

	//设置驱动私有数据
	client->dev.driver_data = (void*)id;
	//标记为已占用
	ap3216c_handle[id].use_flag = 1;
	//绑定i2c_client
	ap3216c_handle[id].client = client;

	//创建设备文件，将ID作为此设备的次设备号
	device = device_create(ap3216c_class, NULL, ap3216c_num+id, NULL, "ap3216c-%d", id);
	if(IS_ERR(device))
	{
		ap3216c_handle[id].use_flag = 0;
		printk("device create failed");
		return PTR_ERR(device);
	}

	return 0;
}

//设备或驱动卸载时执行
static int ap3216c_remove(struct i2c_client *client)
{
	uint32_t id;

	printk("%s\r\n", __FUNCTION__);

	id = (uint32_t)client->dev.driver_data;
	if(!ap3216c_handle[id].use_flag)
	{
		printk("verification failed\r\n");
		return -EINVAL;
	}

	//删除设备文件名
	device_destroy(ap3216c_class, ap3216c_num+id);
	//释放资源
	ap3216c_handle[id].use_flag = 0;

	return 0;
}

static int __init ap3216c_drv_init(void)
{
	int i;
	int result;

	printk("%s\r\n", __FUNCTION__);

	for(i=0; i<AP3216C_NUMBER; i++)
	{
		memset(&ap3216c_handle[i], 0, sizeof(ap3216c_handle[i]));
	}

	//根据次设备号起始值动态注册字符设备号
	result = alloc_chrdev_region(&ap3216c_num, 0, AP3216C_NUMBER, "atk,ap3216c");
	if(result != 0)
	{
		printk("alloc chrdev failed\r\n");
		return result;
	}
	printk("first device major %d, minor %d\r\n", MAJOR(ap3216c_num), MINOR(ap3216c_num));

	//初始化CDEV对象
	cdev_init(&ap3216c_cdev, &ap3216c_ops);
	ap3216c_cdev.owner = THIS_MODULE;
	//向系统添加CDEV对象
	result = cdev_add(&ap3216c_cdev, ap3216c_num, AP3216C_NUMBER);
	if(result != 0)
	{
		unregister_chrdev_region(ap3216c_num, AP3216C_NUMBER);
		printk("add cdev failed\r\n");
		return result;
	}

	//创建class对象
	ap3216c_class = class_create(THIS_MODULE, "ap3216c,class");
	if(IS_ERR(ap3216c_class))
	{
		cdev_del(&ap3216c_cdev);
		unregister_chrdev_region(ap3216c_num, AP3216C_NUMBER);
		printk("class create failed");
		return PTR_ERR(ap3216c_class);
	}

	//注册I2C驱动
	result = i2c_add_driver(&ap3216c_driver);
	if(result != 0)
	{
		class_destroy(ap3216c_class);
		cdev_del(&ap3216c_cdev);
		unregister_chrdev_region(ap3216c_num, AP3216C_NUMBER);
		printk("add cdev failed\r\n");
		return result;
	}

	return result;
}

static void __exit ap3216c_drv_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销I2C驱动
	i2c_del_driver(&ap3216c_driver);
	//销毁class对象
	class_destroy(ap3216c_class);
	//从系统删除CDEV对象
	cdev_del(&ap3216c_cdev);
	//注销字符设备号
	unregister_chrdev_region(ap3216c_num, AP3216C_NUMBER);
}

module_init(ap3216c_drv_init);
module_exit(ap3216c_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("ap3216c_driver");
